# views.py

import pdb

from django.contrib.auth.models import UserManager, User
from django.contrib.auth import login, authenticate
from django.forms.formsets import formset_factory
from django.shortcuts import render_to_response
from django.core.mail import mail_managers
from django.template import RequestContext

from django.http import Http404, HttpResponse

import urllib

import logging
viewslogger = logging.getLogger('psd.register.views')
#reglogger = logging.getLogger( 'psd.register.views(reg)' )

from psd.register.forms import PersonForm, RegRecordForm
from psd.register.models import Person, RegRecord, Event

from psd.settings import DEBUG



    

def contact_reg(g, evt, request ):
    """
    Email the contact email with event details, etc.
    
    SIDE EFFECT: If the user account does not exist, build it and send the password along 
    with everything else.  Also auto-log person in.
    """
    viewslogger.debug( "Contacting %s for event %s" % (g, evt, ) )
    newuser = False
    if not request.user.is_authenticated():
        newuser = True
        if DEBUG:
            ## WARNING: passwords are PSD IDs in debug mode.  Watch this before distribution.
            pw = g.psdid 
        else:
            pw = UserManager().make_random_password()
        viewslogger.debug( "Making new user '%s' '%s'" % (g.psdid, g.email,) )
        user = User.objects.create_user(g.psdid, g.email, pw)
        user = authenticate(username=g.psdid, password=pw)
        if not evt.no_emailing:
            login(request, user)
        viewslogger.info( "Auto-log-on for user '%s'" % (user, ) )
    else:
        viewslogger.info( "contact_reg when user '%s' logged on." % (request.user, ) )
        user = request.user
        pw = 'XXXXX'
        
    ## You can call email_user with args (subject, message, sender).
    ## If you leave out the sender, like here, it fills in the
    ## DEFAULT from settings.py
    #if request == None:
    #    email_body = render_to_response( 'email/registration_email.txt', {'rr' : g, 'event' : evt, 'newuser' : newuser, 'password' : pw } )
    #else:
    if not evt.no_emailing:
        email_body = render_to_response( 'email/registration_email.txt', 
                                         {'rr' : g, 'event' : evt, 'newuser' : newuser, 'password' : pw }, 
                                         context_instance=RequestContext(request) )
        
        user.email_user( "Registration confirmation for %s." % g.psdid, email_body.content, from_email=evt.info_email )
        admin_email_body = render_to_response( 'email/payment_email.txt', { 'rr': g, 'data':'no data--not from paypal'} )
        mail_managers( 'Registration for %s' % (g.psdid,), admin_email_body.content )
    else:
        viewslogger.debug( "Did not send update emails due to event no_emailing flag" )
        
    viewslogger.debug( "contact_reg finished for RR id=%s psdid='%s' '%s'" % (g.id, g.psdid, g) )

    

def mk_person_id(p):
    """ Make a Poly Speed Dating ID, i.e., the initials of the person followed by a 
        three digit number"""
    bignum = 100 + p.id
    id = p.first_name[0] + p.last_name[0] + str(bignum)
    viewslogger.info( "Generated person id '%s' (before uppercasing) for record %s" % (id,p.id) )
    return id.upper()

def mk_group_id(g):
    """ Make a PSD ID for a group by taking the first letter of each name and then
        adding a three digit number and a following G for group"""
    bignum = 100 + g.id
    initials = [p.first_name[0] for p in g.people.all()]
    initials = ''.join(initials)
    id = initials + str(bignum) + 'G'
    viewslogger.info( "Generated group id '%s' (before uppercasing) for record %d" % (id,g.id) )
    return id.upper()

def psdid_stamp_person(p):
    """
    Give a PSD ID to the person and enter that into the database
    """
    viewslogger.debug( "Going to generate PSD ID for %s (%s %s)" % (p.id, p.first_name, p.last_name ) )
    id = mk_person_id(p)
    viewslogger.debug( "PSD ID for %s (%s %s) is %s" % (p.id, p.first_name, p.last_name, id ) )
    p.psdid = id
    p.save()


def set_psdid_ids(g):
    """
    Take new regrecord g and give all people in it their PSD IDs and then generate a 
    group PSD ID by copying the one from the person (if there is only one) or making 
    one from the names of all the people in the group.
    """
    members = g.people.all()

    for p in members:
        psdid_stamp_person(p)
    if len(members) == 1:
        g.psdid = members[0].psdid
    else:
        id = mk_group_id(g)
        g.psdid = id
    g.save()
    viewslogger.info( "set all regrecord and person IDs for %s" % (g,) )







def admin_checkboxes(request):
    PersonFormset = formset_factory(PersonForm)
    if request.method == 'POST':
        pformset = PersonFormset(request.POST)
        #if pformset.is_valid():
            

def set_hidden_reg_fields(rcd, event ):
    """ Initialize various flags for payment and whatnot that users don't directly
        fill out."""
    for field in ['paid', 'cancelled', 'pending', 'here', 'stationary', 'is_group']:
        rcd[field] = False
    #for field in ['notes']:
    #    rcd[field] = ''
    rcd['notes'] = ''
    for field in ['matches', 'oneway']:
        rcd[field] = 0
        
    if event.no_emailing:
        rcd['here'] = True


def updateFromOldForm(newreg, oldreg):
    """Look for an old form for the same event.  If it is there, copy the admin
    fields over, delete the old form, save the new form"""
    for field in ['paid', 'cancelled', 'pending', 'here', 'stationary', 'is_group', 'notes','matches', 'oneway']:
        newreg.__dict__[field] = oldreg.__dict__[field]
           
    # delete old records with the same event.
    RegRecord.objects.filter(event=newreg.event, psdid=newreg.psdid).exclude(id=newreg.id).delete()
    newreg.reregistered=True


def get_last_registration( user, event_name ):
    """
    Return the last registration made by user, for event_name if possible.
    If there is a regrecord for event_name, then return a flag indicating so
    """
    if user.username == '':
        viewslogger.warning( "Returning None,False since username for user '%s' is empty." % (user, ) )
        return (None, False)
    
    viewslogger.info( "Looking for old registration for user '%s' ('%s') and event '%s'" % (user, user.username, event_name) )
    oldreg = RegRecord.objects.filter(psdid=user.username, event=event_name)
    if len(oldreg) == 0:
        oldreg = RegRecord.objects.filter(psdid=user.username).order_by('-id')
    
    if len(oldreg) == 0:
        return (None, False)
    else:
        oldreg = oldreg[0]
        viewslogger.info( "get_last_registration for %s %s returned potential registration %s" % (user, event_name, oldreg) )
        if oldreg.event == event_name:
            return (oldreg, True)
        else:
            return (oldreg, False)
                    


def sign_up_indiv(request, event_name):
    """
    Called when the Individual Registration form is filled out and submitted.
    """
    
    viewslogger.info( "***** sign_up_indiv called for %s" % (event_name, ) )
    try:
        event = Event.objects.get(event=event_name)
    except Event.DoesNotExist:
        return render_to_response( 'error.html', {'message' : "Sorry.  You are trying to register for an event that does not exist or is closed.  Please try again." }, 
                                   context_instance=RequestContext(request)  )

        
    # check to see if registration is closed or frozen
    if event.regfrozen:
        return render_to_response( 'register/regclosed.html' );

    if request.user.is_authenticated:
        viewslogger.info( "User '%s' is authenticated, going to look for old reg records" % (request.user,) )
        (oldreg, is_reregister) = get_last_registration( request.user, event_name )
    else:
        oldreg = None
        is_reregister = False

    if event.regclosed and not is_reregister:
        return render_to_response( 'register/regclosed.html' );

        
    if request.method == 'POST':
        viewslogger.info( "POST call for %s---going to save RegRecord, etc." % event_name )
        pform = PersonForm(request.POST)
        rform = RegRecordForm(request.POST)
        if pform.is_valid() and rform.is_valid():
            pcd = pform.cleaned_data
            rcd = rform.cleaned_data
            if oldreg != None:
                # overwrite associate person object
                p = oldreg.people.all()
                if len(p) > 0:
                        p = p[0]
                        viewslogger.debug( "Loading old person %s with id %s and psdid '%s'" % (p, p.id, p.psdid) )
                        del pcd['psdid']
                        p.__dict__.update(pcd)
                else:
                        p = Person(**pcd)
            else:
                ## user not logged in, check if email already exists, indicating a reregistration without logging in error
                oldemail = RegRecord.objects.filter(email=rcd['email']).count()
                if oldemail == 0:
                    ## no record of email - create new person
                    p = Person(**pcd)    
                else:
                    ## email already registered and user not logged in, user needs to login.
                    return render_to_response('register/returningusererror.html', {'login_required' : 'yes' }, context_instance=RequestContext(request))
            p.save()

            set_hidden_reg_fields(rcd, event )
            rcd['event'] = event.event
            # NEXT LINE SHOULD NOT BE NEEDED!!!!!
            # What the hell is going on????
            del rcd['people']
            r = RegRecord(**rcd)
            r.save()
            r.people.add(p)
            r.save()
            if request.user.is_authenticated():
                viewslogger.info( "Setting psdid of '%s' to logged in user ID of '%s'" % (r, request.user.username, ) )
                r.psdid = request.user.username
                if is_reregister:
                    updateFromOldForm( r, oldreg )
            else:
                set_psdid_ids(r)
            
            if event.no_ssm and r.straightish_male and not is_reregister:
                    r.addNote( "!Need companion!" )
                    
            r.save()
            contact_reg(r, event, request=request )
            return render_to_response('register/payment.html', {'reg': r, 'event': event},
                                       context_instance=RequestContext(request))
        else:
            return render_to_response('register/registration_error.html', {'pform': pform, 'rform': rform}, 
                                      context_instance=RequestContext(request))
    elif request.user.is_authenticated():
        # make form to fill out with old registration information
        if oldreg == None:
                viewslogger.info( "Returning empty indiv form for authenticated user '%s'" % (request.user, ) )
                ## TODO: refactor to avoid repeating code from below.
                pform = PersonForm(initial={'seek_kinkiness': 'EI'})
                rform = RegRecordForm()
        else:
                viewslogger.info( "Returning auto-filled indiv form for authenticated user '%s'" % (request.user, ) )
                rform = RegRecordForm(initial=oldreg.__dict__)
                oldper=oldreg.people.all()
                if len(oldper) > 0:
                    pform = PersonForm(initial=oldper[0].__dict__)
                else:
                    viewslogger.warning( "No people found in old reg record '%s'---going to leave blank" % (oldreg, ) )
                    pform = PersonForm(initial={'seek_kinkiness': 'EI'})
    else:
        # make empty form to fill out
        viewslogger.info( "Returning empty indiv form" )
        pform = PersonForm(initial={'seek_kinkiness': 'EI'})
        rform = RegRecordForm()
        
    return render_to_response('register/registerIndiv.html', {'event': event, 'pform': pform, 'rform': rform, 'is_reregister': is_reregister}, 
                              context_instance=RequestContext(request))




def registration_note(request, event_name="unknown"):
    """Called when note for registration is needed"""
    
    try:
        event = Event.objects.get(event=event_name)
    except Event.DoesNotExist:
        return render_to_response( 'error.html', {'message' : "Sorry.  You are trying to register for an event that does not exist or is closed.  Please try again." }, 
                                   context_instance=RequestContext(request)  )

    return render_to_response( 'register/registration_note.html', {'event':event, 'event_name':event_name },
                               context_instance=RequestContext(request) )







def sign_up_group(request, event_name):
    """
    Called when the Group Registration form is filled out and 
    submitted.
    """
    
    viewslogger.info( "sign_up_group called for %s" % event_name )
    try:
        event = Event.objects.get(event=event_name)
    except Event.DoesNotExist:
        return render_to_response( 'error.html', {'message' : "You are trying to register for an event that does not exist or is closed.  Please try again." }, 
                                   context_instance=RequestContext(request)  )

    if event.regfrozen:
        return render_to_response( 'register/regclosed.html' );

    if request.user.is_authenticated:
        (oldreg, is_reregister) = get_last_registration( request.user, event_name )
    else:
        oldreg = None
        is_reregister = False


    # check to see if registration is closed or frozen
    if event.regclosed and not is_reregister:
        return render_to_response( 'register/regclosed.html' );

    PersonFormset = formset_factory(PersonForm, extra=2, max_num=2)
  
    if request.method == 'POST':
        viewslogger.info( "POST call for %s" % event_name )
        pformset = PersonFormset(request.POST)
        rform = RegRecordForm(request.POST)
        if pformset.is_valid() and rform.is_valid():
            
            rcd = rform.cleaned_data
            
            if oldreg is None:
                ## user not logged in, check if registration already exists
                oldemail = RegRecord.objects.filter(email=rcd['email']).count()
                if oldemail > 0:
                    ## email already registered and user not logged in, user needs to login.
                    return render_to_response('register/returningusererror.html', {'login_required' : 'yes' }, context_instance=RequestContext(request))

            set_hidden_reg_fields(rcd, event)
            rcd['event'] = event.event
            # NEXT LINE SHOULD NOT BE NEEDED!!!!!
            # What the hell is going on????
            del rcd['people']
            r = RegRecord(**rcd)
            r.save()
            
            if not oldreg is None:
                oldpeeps = oldreg.people.all()
                if len(oldpeeps) > len(pformset.forms):
                    return render_to_response( 'error.html', {'message' : "You are registering fewer people than the last time you registered (%d vs. %d).  This is currently not allowed.  Please log-out, register as a brand new user, and then contact us." % (len(oldpeeps), len(pformset.forms)) }, 
                                       context_instance=RequestContext(request)  )
                
                for (pform,p) in zip( pformset.forms, oldpeeps ):
                    if not pform.cleaned_data:
                        return render_to_response( 'error.html', {'message' : "Missing person in registration.  You are registering a different number of people than the last time you registered.  This is currently not allowed.  Please log-out, register as a brand new user, and then contact us." }, 
                                       context_instance=RequestContext(request)  )
                    pcd = pform.cleaned_data
                    del pcd['psdid']
                    p.__dict__.update(pcd)
                    p.save()
                    r.people.add(p)
                    p.save()
            else:
                for form in pformset.forms:
                    if not form.cleaned_data:
                        continue
                    pcd = form.cleaned_data
                    p = Person(**pcd)
                    p.save()
                    r.people.add(p)
                    p.save()

            if r.people.count() > 1:
                r.is_group = True
            r.save()
            
            if request.user.is_authenticated():
                r.psdid = request.user.username
                if is_reregister:
                    updateFromOldForm( r, oldreg )
                r.save()
            else:
                set_psdid_ids(r)
            contact_reg(r, event, request=request )
            return render_to_response('register/payment.html', {'reg': r, 'event': event },
                                       context_instance=RequestContext(request))
        else:
            return render_to_response('register/registration_error.html', {'pformset': pformset, 'rform': rform}, context_instance=RequestContext(request))
    elif not oldreg is None:
        rform = RegRecordForm(initial=oldreg.__dict__)
        oldper=oldreg.people.all()
        inits = []
        for op in oldper:
            inits.append(op.__dict__)
        pformset = PersonFormset( initial=inits )
    else:
        pformset = PersonFormset()
        rform = RegRecordForm()
    return render_to_response('register/registerGroup.html', {'event': event, 'pformset': pformset, 'rform': rform, 'is_reregister':is_reregister}, context_instance=RequestContext(request))






class PaypalPaymentEndpoint:
    
    verify_url = "https://www.paypal.com/cgi-bin/webscr"
       
    def __call__(self, request):
        viewslogger.debug( "PayPalPaymentEndpoint called request_meth = %s" % (request.method, ) )
        ret = None
        #data = { 'apple':20, 'pear':'banana'}
        if request.method == 'POST':
            data = dict(request.POST.items())
            viewslogger.debug( "got post from %s with data %s ", request.get_host(), data )
            # We need to post that BACK to PayPal to confirm it
            args = { 'cmd': '_notify-validate', }
            args.update(data)

            viewslogger.debug( "Validating ipn with Paypal at %s", self.verify_url)

            if urllib.urlopen(self.verify_url, urllib.urlencode(args)).read() == 'VERIFIED':
                cstring = "NO CUSTOM"
                if 'custon' in data:
                    cstring = data['custom']
                payemail = "NO PAYER EMAIL"
                if 'payer_email' in data:
                    payemail = data['payer_email']

                viewslogger.debug( "Got VERIFIED from paypal for %s with custom: %s", payemail, cstring )
                ret = self.valid_ipn(data)
            else:
                #TODO: email someone?
                viewslogger.debug( "Invalid IPN from paypal with data %s", args )
                mail_managers( 'PayPal Failure', 'Data object %s' % (data,) )
                ret = self.invalid_ipn(data)

        if ret:
            return ret
        else:
            #data['valid'] = False
            #data['custom'] = 'uptown1-TB119'
            #data['txn_id'] = 'TEST_TXN_!00'
            #return self.valid_ipn(data) 
            #render_to_response('finished.html', {'data': data} )
            return HttpResponse('Nothing to see here')
            
    
    def valid_ipn(self, data):
        """
        data has something like: (See: https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro#id091F0M006Y4 )
            {
                'business': 'info@polyspeeddating.com',
                'charset': 'windows-1252',
                'cmd': '_notify-validate',
                'first_name': '',
                'last_name': '',
                'mc_currency': 'USD',
                'mc_fee': '0.01',
                'mc_gross': '0.01',
                'notify_version': '2.6',
                'payer_business_name': '...',
                'payer_email': 'payer@example.com',
                'payer_id': 'paypal id',
                'payer_status': 'verified',
                'payment_date': '11:45:00 Jan 30, 2011 PDT',
                'payment_fee': '',
                'payment_gross': '',
                'payment_status': 'Completed',
                'payment_type': 'instant',
                'receiver_email': 'info@polyspeeddating.com',
                'receiver_id': 'S8XGHLYDW9T3S',
                'residence_country': 'US',
                'txn_id': '61E67681CH3238416',
                'txn_type': 'express_checkout',
                'verify_sign': 'AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS'
                'custom': 'uptown1-LM101'
            }
        """
        # do something with all this data.
        viewslogger.debug("paypal hit--using data: %s", data)

        if 'custom' in data:
            status = data['payment_status']
            if status != 'Completed':
                viewslogger.debug(" got non-completed paypal IPN with status: %s", status)
                return HttpResponse('Ignoring ' + status + ' response from paypal.')
            
            ec = data['custom']
            ec = ec.split( '-' )
            if len(ec) == 2:
                data['psdid'] = ec[1]
                data['event'] = ec[0]

                #find regrecord for psdid and event:
                viewslogger.debug(" getting regrecord for %s, %s", ec[1], ec[0])
                paidreg = RegRecord.objects.filter(psdid=ec[1], event=ec[0])
                if len(paidreg) == 0:
                    # no regrecord found or invalid psdid.
                    # TODO: log and mail admins...
                    viewslogger.debug(" could not find regrecord for %s", data)
                    mail_managers( 'PayPal Failure: could not find psdid for payment', 'Data object %s' % (data,) )
                else:
                    viewslogger.debug(" updating regrecord for %s", ec[1])
                    rr = paidreg[0]
                    rr.paid = True
                    rr.addNote( "paypal transation id: " + data['txn_id'] )
                    rr.save()
                    viewslogger.debug( "going to send mail to managers about this transaction" )
                    email_bod=render_to_response( 'email/payment_email.txt', locals() )
                    mail_managers( 'PayPal Payment for %s' % (rr.psdid,), email_bod.content )
            else:
                viewslogger.debug("invalid custom field")
                mail_managers( 'PayPal Failure: invalid custom field (or no custom field)', 'Data object %s' % (data,) )        
        else:
            viewslogger.debug("missing custom field")
            mail_managers( 'PayPal Failure: invalid custom field (or no custom field)', 'Data object %s' % (data,) )                    

        return render_to_response('register/finished.html', {'data': data, 'valid':True} )


    
    def invalid_ipn(self, data):
        # Log and bring out Reason?.
        return render_to_response('register/finished.html', {'data': data, 'valid':False} )




